package cn.iwgang.countdownview;


import cn.iwgang.countdownview.utils.TextUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;

/**
 * Base Countdown
 * Created by iWgang on 16/6/18.
 * https://github.com/iwgang/CountdownView
 */
class BaseCountdown {
    private static final String DEFAULT_SUFFIX = ":";
    private static final float DEFAULT_SUFFIX_LR_MARGIN = 3; // dp

    public int mDay;
    int mHour;
    int mMinute;
    int mSecond;
    int mMillisecond;

    public boolean isShowDay;
    boolean isShowHour;
    boolean isShowMinute;
    boolean isShowSecond;
    boolean isShowMillisecond;


    public boolean isConvertDaysToHours;
    public boolean mHasSetIsShowDay;
    boolean mHasSetIsShowHour;


    protected Context mContext;
    protected String mSuffix;
    String mSuffixDay;
    String mSuffixHour;
    String mSuffixMinute;
    String mSuffixSecond;
    String mSuffixMillisecond;

    protected float mSuffixDayTextWidth;
    float mSuffixHourTextWidth;
    float mSuffixMinuteTextWidth;
    float mSuffixSecondTextWidth;
    float mSuffixMillisecondTextWidth;

    protected boolean isDayLargeNinetyNine;
    protected Paint mTimeTextPaint;
    Paint mSuffixTextPaint;
    Paint mMeasureHourWidthPaint;

    protected float mLeftPaddingSize;
    protected float mSuffixDayLeftMargin;
    float mSuffixDayRightMargin;

    protected float mSuffixSecondLeftMargin;
    float mSuffixSecondRightMargin;

    protected float mSuffixHourLeftMargin;
    float mSuffixHourRightMargin;

    protected float mSuffixMinuteLeftMargin;
    float mSuffixMinuteRightMargin;

    protected float mSuffixMillisecondLeftMargin;
    protected float mSuffixDayTextBaseline;
    float mSuffixHourTextBaseline;
    float mSuffixMinuteTextBaseline;
    float mSuffixSecondTextBaseline;
    float mSuffixMillisecondTextBaseline;

    protected float mTimeTextWidth;
    float mTimeTextHeight;
    float mTimeTextBottom;

    protected int mSuffixGravity = 1;

    private boolean hasSetSuffixDay;
    boolean hasSetSuffixHour;
    boolean hasSetSuffixMinute;
    boolean hasSetSuffixSecond;
    boolean hasSetSuffixMillisecond;

    private boolean hasCustomSomeSuffix;
    private float mSuffixLRMargin;
    private Color mTimeTextColor = Color.BLUE;
    private int mTimeTextSize;
    private boolean isTimeTextBold;
    private Color mSuffixTextColor = Color.RED;
    private int mSuffixTextSize;
    private boolean isSuffixTextBold;
    private float mDayTimeTextWidth;
    float mHourTimeTextWidth;

    private float mTimeTextBaseline;

    private float mTempSuffixDayLeftMargin;
    float mTempSuffixDayRightMargin;

    private float mTempSuffixHourLeftMargin;
    float mTempSuffixHourRightMargin;

    private float mTempSuffixMinuteLeftMargin;
    float mTempSuffixMinuteRightMargin;

    private float mTempSuffixSecondLeftMargin;
    float mTempSuffixSecondRightMargin;

    private float mTempSuffixMillisecondLeftMargin;
    private String mTempSuffixMinute;
    String mTempSuffixSecond;

    private boolean isHideTimeBackground = true;
    private Component mComponent;


    public void initStyleAttr(Component component, Context context, AttrSet attrs) {
        mComponent = component;
        mContext = context;

        boolean presentIsTimeTextBold = attrs.getAttr("isTimeTextBold").isPresent();
        if (presentIsTimeTextBold) {
            isTimeTextBold = attrs.getAttr("isTimeTextBold").get().getBoolValue();
        }

        boolean presentTimeTextSize = attrs.getAttr("timeTextSize").isPresent();
        if (presentTimeTextSize) {

            mTimeTextSize = attrs.getAttr("timeTextSize").get().getDimensionValue();

        }


        boolean presentTimeTextColor = attrs.getAttr("timeTextColor").isPresent();
        if (presentTimeTextColor) {

            mTimeTextColor = attrs.getAttr("timeTextColor").get().getColorValue();

        }

        boolean presentIsShowDay = attrs.getAttr("isShowDay").isPresent();
        if (presentIsShowDay) {

            isShowDay = attrs.getAttr("isShowDay").get().getBoolValue();
            mHasSetIsShowDay = true;
        } else {

            mHasSetIsShowDay = false;
        }


        boolean presentIsShowHour = attrs.getAttr("isShowHour").isPresent();
        if (presentIsShowHour) {

            isShowHour = attrs.getAttr("isShowHour").get().getBoolValue();
            mHasSetIsShowHour = true;
        } else {
            mHasSetIsShowHour = false;
        }


        boolean presentIsShowMinute = attrs.getAttr("isShowMinute").isPresent();
        if (presentIsShowMinute) {

            isShowMinute = attrs.getAttr("isShowMinute").get().getBoolValue();
        }


        boolean presentIsShowSecond = attrs.getAttr("isShowSecond").isPresent();
        if (presentIsShowSecond) {

            isShowSecond = attrs.getAttr("isShowSecond").get().getBoolValue();
        }

        boolean presentIsShowMillisecond = attrs.getAttr("isShowMillisecond").isPresent();
        if (presentIsShowMillisecond) {

            isShowMillisecond = attrs.getAttr("isShowMillisecond").get().getBoolValue();
        }

        boolean presentIsHideTimeBackground = attrs.getAttr("isHideTimeBackground").isPresent();
        if (presentIsHideTimeBackground) {

            isHideTimeBackground = attrs.getAttr("isHideTimeBackground").get().getBoolValue();
        }

        if (isHideTimeBackground) {

            boolean presentisConvertDaysToHours = attrs.getAttr("isConvertDaysToHours").isPresent();
            if (presentisConvertDaysToHours) {

                isConvertDaysToHours = attrs.getAttr("isConvertDaysToHours").get().getBoolValue();
            }

        }

        boolean presentIsSuffixTextBold = attrs.getAttr("isSuffixTextBold").isPresent();
        if (presentIsSuffixTextBold) {

            isSuffixTextBold = attrs.getAttr("isSuffixTextBold").get().getBoolValue();
        }


        boolean presentsuffixTextSize = attrs.getAttr("suffixTextSize").isPresent();
        if (presentsuffixTextSize) {

            mSuffixTextSize = attrs.getAttr("suffixTextSize").get().getDimensionValue();
        }

        boolean presentSuffixTextColor = attrs.getAttr("suffixTextColor").isPresent();
        if (presentSuffixTextColor) {

            mSuffixTextColor = attrs.getAttr("suffixTextColor").get().getColorValue();
        }

        boolean presentSuffix = attrs.getAttr("suffix").isPresent();
        if (presentSuffix) {

            mSuffix = attrs.getAttr("suffix").get().getStringValue();
        }


        boolean presentSuffixDay = attrs.getAttr("suffixDay").isPresent();
        if (presentSuffixDay) {

            mSuffixDay = attrs.getAttr("suffixDay").get().getStringValue();
        }

        boolean presentSuffixHour = attrs.getAttr("suffixHour").isPresent();
        if (presentSuffixHour) {
            mSuffixHour = attrs.getAttr("suffixHour").get().getStringValue();
        }
        boolean presentSuffixMinute = attrs.getAttr("suffixMinute").isPresent();
        if (presentSuffixMinute) {
            mSuffixMinute = attrs.getAttr("suffixMinute").get().getStringValue();
        }

        boolean presentSuffixSecond = attrs.getAttr("suffixSecond").isPresent();
        if (presentSuffixSecond) {
            mSuffixSecond = attrs.getAttr("suffixSecond").get().getStringValue();
        }

        boolean presentSuffixMillisecond = attrs.getAttr("suffixMillisecond").isPresent();
        if (presentSuffixMillisecond) {
            mSuffixMillisecond = attrs.getAttr("suffixMillisecond").get().getStringValue();
        }
        boolean presentSuffixGravity = attrs.getAttr("suffixGravity").isPresent();
        if (presentSuffixGravity) {
            String mSuffixGravitysss = attrs.getAttr("suffixGravity").get().getStringValue();
            if ("top".equals(mSuffixGravitysss)) {
                mSuffixGravity = 0;
            } else if ("center".equals(mSuffixGravitysss)) {
                mSuffixGravity = 1;
            } else if ("bottom".equals(mSuffixGravitysss)) {
                mSuffixGravity = 2;
            } else {
                mSuffixGravity = 1;
            }

        }


        boolean presentSuffixLRMargin = attrs.getAttr("suffixLRMargin").isPresent();
        if (presentSuffixLRMargin) {
            mSuffixLRMargin = attrs.getAttr("suffixLRMargin").get().getIntegerValue();
        }

        boolean presentSuffixDayLeftMargin = attrs.getAttr("suffixDayLeftMargin").isPresent();
        if (presentSuffixDayLeftMargin) {
            mSuffixDayLeftMargin = attrs.getAttr("suffixDayLeftMargin").get().getIntegerValue();
        }

        boolean presentSuffixDayRightMargin = attrs.getAttr("suffixDayRightMargin").isPresent();
        if (presentSuffixDayRightMargin) {
            mSuffixDayRightMargin = attrs.getAttr("suffixDayRightMargin").get().getIntegerValue();
        }


        boolean presentSuffixHourLeftMargin = attrs.getAttr("suffixHourLeftMargin").isPresent();
        if (presentSuffixHourLeftMargin) {
            mSuffixHourLeftMargin = attrs.getAttr("suffixHourLeftMargin").get().getIntegerValue();
        }

        boolean presentSuffixHourRightMargin = attrs.getAttr("suffixHourRightMargin").isPresent();
        if (presentSuffixHourRightMargin) {
            mSuffixHourRightMargin = attrs.getAttr("suffixHourRightMargin").get().getIntegerValue();
        }
        boolean presentSuffixMinuteLeftMargin = attrs.getAttr("suffixMinuteLeftMargin").isPresent();
        if (presentSuffixMinuteLeftMargin) {
            mSuffixMinuteLeftMargin = attrs.getAttr("suffixMinuteLeftMargin").get().getIntegerValue();
        }

        boolean presentSuffixMinuteRightMargin = attrs.getAttr("suffixMinuteRightMargin").isPresent();
        if (presentSuffixMinuteRightMargin) {
            mSuffixMinuteRightMargin = attrs.getAttr("suffixMinuteRightMargin").get().getIntegerValue();
        }

        boolean presentSuffixSecondLeftMargin = attrs.getAttr("suffixSecondLeftMargin").isPresent();
        if (presentSuffixSecondLeftMargin) {
            mSuffixSecondLeftMargin = attrs.getAttr("suffixSecondLeftMargin").get().getIntegerValue();
        }
        boolean presentSuffixSecondRightMargin = attrs.getAttr("suffixSecondRightMargin").isPresent();
        if (presentSuffixSecondRightMargin) {
            mSuffixSecondRightMargin = attrs.getAttr("suffixSecondRightMargin").get().getIntegerValue();
        }

        boolean presentSuffixMillisecondLeftMargin = attrs.getAttr("suffixMillisecondLeftMargin").isPresent();
        if (presentSuffixMillisecondLeftMargin) {
            mSuffixMillisecondLeftMargin = attrs.getAttr("suffixMillisecondLeftMargin").get().getIntegerValue();
        }


        initTempSuffixMargin();

        // time validate
        if (!isShowDay && !isShowHour && !isShowMinute) isShowSecond = true;
        if (!isShowSecond) isShowMillisecond = false;




    }

    public void initialize() {

        initSuffixBase();
        // initialize
        initPaint();
        initSuffix();
        // regular time data
        // pick one of two (minute and second)
//        if (!isShowMinute && !isShowSecond) isShowSecond = true;
        if (!isShowSecond) isShowMillisecond = false;

        initTimeTextBaseInfo();
    }

    private void initSuffixBase() {

        hasSetSuffixDay = !TextUtils.isEmpty(mSuffixDay);
        hasSetSuffixHour = !TextUtils.isEmpty(mSuffixHour);
        hasSetSuffixMinute = !TextUtils.isEmpty(mSuffixMinute);
        hasSetSuffixSecond = !TextUtils.isEmpty(mSuffixSecond);
        hasSetSuffixMillisecond = !TextUtils.isEmpty(mSuffixMillisecond);

        if ((isShowDay && hasSetSuffixDay)
                || (isShowHour && hasSetSuffixHour)
                || (isShowMinute && hasSetSuffixMinute)
                || (isShowSecond && hasSetSuffixSecond)
                || (isShowMillisecond && hasSetSuffixMillisecond)) {
            hasCustomSomeSuffix = true;
        }

        mTempSuffixMinute = mSuffixMinute;
        mTempSuffixSecond = mSuffixSecond;
    }

    private void initTempSuffixMargin() {

        // temporarily saved suffix left and right margins
        mTempSuffixDayLeftMargin = mSuffixDayLeftMargin;
        mTempSuffixDayRightMargin = mSuffixDayRightMargin;
        mTempSuffixHourLeftMargin = mSuffixHourLeftMargin;
        mTempSuffixHourRightMargin = mSuffixHourRightMargin;
        mTempSuffixMinuteLeftMargin = mSuffixMinuteLeftMargin;
        mTempSuffixMinuteRightMargin = mSuffixMinuteRightMargin;
        mTempSuffixSecondLeftMargin = mSuffixSecondLeftMargin;
        mTempSuffixSecondRightMargin = mSuffixSecondRightMargin;
        mTempSuffixMillisecondLeftMargin = mSuffixMillisecondLeftMargin;
    }

    /**
     * initialize Paint
     */
    protected void initPaint() {

        // time text
        mTimeTextPaint = new Paint();
        mTimeTextPaint.setAntiAlias(true);
        mTimeTextPaint.setColor(mTimeTextColor);
        mTimeTextPaint.setTextAlign(TextAlignment.CENTER);
        mTimeTextPaint.setTextSize(mTimeTextSize);
        if (isTimeTextBold) {
            mTimeTextPaint.setFakeBoldText(true);
        }

        // suffix text
        mSuffixTextPaint = new Paint();
        mSuffixTextPaint.setAntiAlias(true);
        mSuffixTextPaint.setColor(mSuffixTextColor);
        mSuffixTextPaint.setTextSize(mSuffixTextSize);
        if (isSuffixTextBold) {
            mSuffixTextPaint.setFakeBoldText(true);
        }

        mMeasureHourWidthPaint = new Paint();
        mMeasureHourWidthPaint.setTextSize(mTimeTextSize);
        if (isTimeTextBold) {
            mMeasureHourWidthPaint.setFakeBoldText(true);
        }
    }

    private void initSuffix() {

        boolean isSuffixNull = true;
        float mSuffixTextWidth = 0;
        float mDefSuffixTextWidth = mSuffixTextPaint.measureText(DEFAULT_SUFFIX);

        if (!TextUtils.isEmpty(mSuffix)) {
            isSuffixNull = false;
            mSuffixTextWidth = mSuffixTextPaint.measureText(mSuffix);
        }

        if (isShowDay) {
            if (hasSetSuffixDay) {
                mSuffixDayTextWidth = mSuffixTextPaint.measureText(mSuffixDay);
            } else {
                if (!isSuffixNull) {
                    mSuffixDay = mSuffix;
                    mSuffixDayTextWidth = mSuffixTextWidth;
                } else if (!hasCustomSomeSuffix) {
                    mSuffixDay = DEFAULT_SUFFIX;
                    mSuffixDayTextWidth = mDefSuffixTextWidth;
                }
            }
        } else {
            mSuffixDayTextWidth = 0;
        }

        if (isShowHour) {
            if (hasSetSuffixHour) {
                mSuffixHourTextWidth = mSuffixTextPaint.measureText(mSuffixHour);
            } else {
                if (!isSuffixNull) {
                    mSuffixHour = mSuffix;
                    mSuffixHourTextWidth = mSuffixTextWidth;
                } else if (!hasCustomSomeSuffix) {
                    mSuffixHour = DEFAULT_SUFFIX;
                    mSuffixHourTextWidth = mDefSuffixTextWidth;
                }
            }
        } else {
            mSuffixHourTextWidth = 0;
        }

        if (isShowMinute) {
            if (hasSetSuffixMinute) {
                mSuffixMinuteTextWidth = mSuffixTextPaint.measureText(mSuffixMinute);
            } else if (isShowSecond) {
                if (!isSuffixNull) {
                    mSuffixMinute = mSuffix;
                    mSuffixMinuteTextWidth = mSuffixTextWidth;
                } else if (!hasCustomSomeSuffix) {
                    mSuffixMinute = DEFAULT_SUFFIX;
                    mSuffixMinuteTextWidth = mDefSuffixTextWidth;
                }
            } else {
                mSuffixMinuteTextWidth = 0;
            }
        } else {
            mSuffixMinuteTextWidth = 0;
        }

        if (isShowSecond) {
            if (hasSetSuffixSecond) {
                mSuffixSecondTextWidth = mSuffixTextPaint.measureText(mSuffixSecond);
            } else if (isShowMillisecond) {
                if (!isSuffixNull) {
                    mSuffixSecond = mSuffix;
                    mSuffixSecondTextWidth = mSuffixTextWidth;
                } else if (!hasCustomSomeSuffix) {
                    mSuffixSecond = DEFAULT_SUFFIX;
                    mSuffixSecondTextWidth = mDefSuffixTextWidth;
                }
            } else {
                mSuffixSecondTextWidth = 0;
            }
        } else {
            mSuffixSecondTextWidth = 0;
        }

        if (isShowMillisecond && hasCustomSomeSuffix && hasSetSuffixMillisecond) {
            mSuffixMillisecondTextWidth = mSuffixTextPaint.measureText(mSuffixMillisecond);
        } else {
            mSuffixMillisecondTextWidth = 0;
        }

        initSuffixMargin();
    }

    /**
     * initialize suffix margin
     */
    private void initSuffixMargin() {

        int defSuffixLRMargin = Utils.dp2px(mContext, DEFAULT_SUFFIX_LR_MARGIN);
        boolean isSuffixLRMarginNull = true;

        if (mSuffixLRMargin >= 0) {
            isSuffixLRMarginNull = false;
        }

        if (isShowDay && mSuffixDayTextWidth > 0) {
            if (mSuffixDayLeftMargin < 0) {
                if (!isSuffixLRMarginNull) {
                    mSuffixDayLeftMargin = mSuffixLRMargin;
                } else {
                    mSuffixDayLeftMargin = defSuffixLRMargin;
                }
            }

            if (mSuffixDayRightMargin < 0) {
                if (!isSuffixLRMarginNull) {
                    mSuffixDayRightMargin = mSuffixLRMargin;
                } else {
                    mSuffixDayRightMargin = defSuffixLRMargin;
                }
            }
        } else {
            mSuffixDayLeftMargin = 0;
            mSuffixDayRightMargin = 0;
        }

        if (isShowHour && mSuffixHourTextWidth > 0) {
            if (mSuffixHourLeftMargin < 0) {
                if (!isSuffixLRMarginNull) {
                    mSuffixHourLeftMargin = mSuffixLRMargin;
                } else {
                    mSuffixHourLeftMargin = defSuffixLRMargin;
                }
            }

            if (mSuffixHourRightMargin < 0) {
                if (!isSuffixLRMarginNull) {
                    mSuffixHourRightMargin = mSuffixLRMargin;
                } else {
                    mSuffixHourRightMargin = defSuffixLRMargin;
                }
            }
        } else {
            mSuffixHourLeftMargin = 0;
            mSuffixHourRightMargin = 0;
        }

        if (isShowMinute && mSuffixMinuteTextWidth > 0) {
            if (mSuffixMinuteLeftMargin < 0) {
                if (!isSuffixLRMarginNull) {
                    mSuffixMinuteLeftMargin = mSuffixLRMargin;
                } else {
                    mSuffixMinuteLeftMargin = defSuffixLRMargin;
                }
            }

            if (isShowSecond) {
                if (mSuffixMinuteRightMargin < 0) {
                    if (!isSuffixLRMarginNull) {
                        mSuffixMinuteRightMargin = mSuffixLRMargin;
                    } else {
                        mSuffixMinuteRightMargin = defSuffixLRMargin;
                    }
                }
            } else {
                mSuffixMinuteRightMargin = 0;
            }
        } else {
            mSuffixMinuteLeftMargin = 0;
            mSuffixMinuteRightMargin = 0;
        }

        if (isShowSecond) {
            if (mSuffixSecondTextWidth > 0) {
                if (mSuffixSecondLeftMargin < 0) {
                    if (!isSuffixLRMarginNull) {
                        mSuffixSecondLeftMargin = mSuffixLRMargin;
                    } else {
                        mSuffixSecondLeftMargin = defSuffixLRMargin;
                    }
                }

                if (isShowMillisecond) {
                    if (mSuffixSecondRightMargin < 0) {
                        if (!isSuffixLRMarginNull) {
                            mSuffixSecondRightMargin = mSuffixLRMargin;
                        } else {
                            mSuffixSecondRightMargin = defSuffixLRMargin;
                        }
                    }
                } else {
                    mSuffixSecondRightMargin = 0;
                }
            } else {
                mSuffixSecondLeftMargin = 0;
                mSuffixSecondRightMargin = 0;
            }

            if (isShowMillisecond && mSuffixMillisecondTextWidth > 0) {
                if (mSuffixMillisecondLeftMargin < 0) {
                    if (!isSuffixLRMarginNull) {
                        mSuffixMillisecondLeftMargin = mSuffixLRMargin;
                    } else {
                        mSuffixMillisecondLeftMargin = defSuffixLRMargin;
                    }
                }
            } else {
                mSuffixMillisecondLeftMargin = 0;
            }
        } else {
            mSuffixSecondLeftMargin = 0;
            mSuffixSecondRightMargin = 0;
            mSuffixMillisecondLeftMargin = 0;
        }
        mComponent.invalidate();
    }

    protected void initTimeTextBaseInfo() {

        // initialize time text width and height
        Rect rect = new Rect();
        Rect textBounds = mTimeTextPaint.getTextBounds("00");
        mTimeTextWidth = textBounds.getWidth();
        mTimeTextHeight = textBounds.getHeight();
        mTimeTextBottom = textBounds.bottom;

    }

    private void initTimeTextBaseline(int viewHeight, int viewPaddingTop, int viewPaddingBottom) {
        if (viewPaddingTop == viewPaddingBottom) {
            // center
            mTimeTextBaseline = viewHeight / 2 + mTimeTextHeight / 2 - mTimeTextBottom;
        } else {
            // padding top
            mTimeTextBaseline = viewHeight - (viewHeight - viewPaddingTop) + mTimeTextHeight - mTimeTextBottom;
        }

        if (isShowDay && mSuffixDayTextWidth > 0) {
            mSuffixDayTextBaseline = getSuffixTextBaseLine(mSuffixDay);
        }

        if (isShowHour && mSuffixHourTextWidth > 0) {
            mSuffixHourTextBaseline = getSuffixTextBaseLine(mSuffixHour);
        }

        if (isShowMinute && mSuffixMinuteTextWidth > 0) {
            mSuffixMinuteTextBaseline = getSuffixTextBaseLine(mSuffixMinute);
        }

        if (mSuffixSecondTextWidth > 0) {
            mSuffixSecondTextBaseline = getSuffixTextBaseLine(mSuffixSecond);
        }

        if (isShowMillisecond && mSuffixMillisecondTextWidth > 0) {
            mSuffixMillisecondTextBaseline = getSuffixTextBaseLine(mSuffixMillisecond);
        }
    }

    private float getSuffixTextBaseLine(String suffixText) {
//        Rect tempRect = new Rect();
        Rect tempRect = mSuffixTextPaint.getTextBounds(suffixText);

        float ret;
        switch (mSuffixGravity) {
            case 0:
                // top
                ret = mTimeTextBaseline - mTimeTextHeight - tempRect.top;
                break;
            default:
            case 1:
                // center
                ret = mTimeTextBaseline - mTimeTextHeight / 2 + tempRect.getHeight() / 2;
                break;
            case 2:
                // bottom
                ret = mTimeTextBaseline - tempRect.bottom;
                break;
        }

        return ret;
    }

    protected final float getAllContentWidthBase(float timeWidth) {
        float width = (mSuffixDayTextWidth + mSuffixHourTextWidth + mSuffixMinuteTextWidth + mSuffixSecondTextWidth + mSuffixMillisecondTextWidth);
        width += (mSuffixDayLeftMargin + mSuffixDayRightMargin + mSuffixHourLeftMargin + mSuffixHourRightMargin
                + mSuffixMinuteLeftMargin + mSuffixMinuteRightMargin + mSuffixSecondLeftMargin + mSuffixSecondRightMargin + mSuffixMillisecondLeftMargin);

        if (isConvertDaysToHours) {
            width += getDayAndHourContentWidth();
        } else if (isShowHour) {
            width += timeWidth;
        }

        if (isShowMinute) {
            width += timeWidth;
        }

        if (isShowSecond) {
            width += timeWidth;
        }

        if (isShowMillisecond) {
            width += timeWidth;
        }
        return width;
    }

    private float getDayAndHourContentWidth() {
        float width = 0;

        Rect tempRect;

        if (isShowDay) {
            String tempDay = Utils.formatNum(mDay);
            tempRect = mTimeTextPaint.getTextBounds(tempDay);
            mDayTimeTextWidth = tempRect.getWidth();

            width += mDayTimeTextWidth;
        }

        if (isShowHour) {
            String tempHour = Utils.formatNum(mHour);
            tempRect = mMeasureHourWidthPaint.getTextBounds(tempHour);
            mHourTimeTextWidth = tempRect.getWidth();

            width += mHourTimeTextWidth;
        }

        return width;
    }

    /**
     * get all view width
     *
     * @return all view width
     */
    public int getAllContentWidth() {
        float width = getAllContentWidthBase(mTimeTextWidth);

        if (!isConvertDaysToHours && isShowDay) {
            if (isDayLargeNinetyNine) {
//                Rect rect = new Rect();
                String tempDay = String.valueOf(mDay);
                Rect textBounds = mTimeTextPaint.getTextBounds(tempDay);
                mDayTimeTextWidth = textBounds.getWidth();
                width += mDayTimeTextWidth;
            } else {
                mDayTimeTextWidth = mTimeTextWidth;
                width += mTimeTextWidth;
            }
        }

        return (int) Math.ceil(width);
    }

    public int getAllContentHeight() {
        return (int) mTimeTextHeight;
    }

    public void onMeasure(Component v, int viewWidth, int viewHeight, int allContentWidth, int allContentHeight) {
        initTimeTextBaseline(viewHeight, v.getPaddingTop(), v.getPaddingBottom());
        mLeftPaddingSize = v.getPaddingLeft() == v.getPaddingRight() ? (viewWidth - allContentWidth) / 2 : v.getPaddingLeft();
    }

    public void onDraw(Component component, Canvas canvas) {
        // not background
        float mHourLeft;
        float mMinuteLeft;
        float mSecondLeft;

        if (isShowDay) {
            // draw day text
            canvas.drawText(mTimeTextPaint, Utils.formatNum(mDay), mLeftPaddingSize + mDayTimeTextWidth / 2, mTimeTextBaseline);
            if (mSuffixDayTextWidth > 0) {
                // draw day suffix
                canvas.drawText(mSuffixTextPaint, mSuffixDay, mLeftPaddingSize + mDayTimeTextWidth + mSuffixDayLeftMargin, mSuffixDayTextBaseline);
            }

            // hour left point
            mHourLeft = mLeftPaddingSize + mDayTimeTextWidth + mSuffixDayTextWidth + mSuffixDayLeftMargin + mSuffixDayRightMargin;
        } else {
            // hour left point
            mHourLeft = mLeftPaddingSize;
        }

        if (isShowHour) {
            // draw hour text
            float curTimeTextWidth = isConvertDaysToHours ? mHourTimeTextWidth : mTimeTextWidth;
            canvas.drawText(mTimeTextPaint, Utils.formatNum(mHour), mHourLeft + curTimeTextWidth / 2, mTimeTextBaseline);
            if (mSuffixHourTextWidth > 0) {
                // draw hour suffix
                canvas.drawText(mSuffixTextPaint, mSuffixHour, mHourLeft + curTimeTextWidth + mSuffixHourLeftMargin, mSuffixHourTextBaseline);
            }

            // minute left point
            mMinuteLeft = mHourLeft + curTimeTextWidth + mSuffixHourTextWidth + mSuffixHourLeftMargin + mSuffixHourRightMargin;
        } else {
            // minute left point
            mMinuteLeft = mHourLeft;
        }

        if (isShowMinute) {
            // draw minute text
            canvas.drawText(mTimeTextPaint, Utils.formatNum(mMinute), mMinuteLeft + mTimeTextWidth / 2, mTimeTextBaseline);
            if (mSuffixMinuteTextWidth > 0) {
                // draw minute suffix
                canvas.drawText(mSuffixTextPaint, mSuffixMinute, mMinuteLeft + mTimeTextWidth + mSuffixMinuteLeftMargin, mSuffixMinuteTextBaseline);
            }

            // second left point
            mSecondLeft = mMinuteLeft + mTimeTextWidth + mSuffixMinuteTextWidth + mSuffixMinuteLeftMargin + mSuffixMinuteRightMargin;
        } else {
            // second left point
            mSecondLeft = mMinuteLeft;
        }

        if (isShowSecond) {
            // draw second text
            canvas.drawText(mTimeTextPaint, Utils.formatNum(mSecond), mSecondLeft + mTimeTextWidth / 2, mTimeTextBaseline);
            if (mSuffixSecondTextWidth > 0) {
                // draw second suffix
                canvas.drawText(mSuffixTextPaint, mSuffixSecond, mSecondLeft + mTimeTextWidth + mSuffixSecondLeftMargin, mSuffixSecondTextBaseline);
            }

            if (isShowMillisecond) {
                // millisecond left point
                float mMillisecondLeft = mSecondLeft + mTimeTextWidth + mSuffixSecondTextWidth + mSuffixSecondLeftMargin + mSuffixSecondRightMargin;
                // draw millisecond text
                canvas.drawText(mTimeTextPaint, Utils.formatMillisecond(mMillisecond), mMillisecondLeft + mTimeTextWidth / 2, mTimeTextBaseline);
                if (mSuffixMillisecondTextWidth > 0) {
                    // draw millisecond suffix
                    canvas.drawText(mSuffixTextPaint, mSuffixMillisecond, mMillisecondLeft + mTimeTextWidth + mSuffixMillisecondLeftMargin, mSuffixMillisecondTextBaseline);
                }
            }
        }
    }

    public boolean refTimeShow(boolean isShowDay, boolean isShowHour, boolean isShowMinute, boolean isShowSecond, boolean isShowMillisecond) {
        if (!isShowSecond) isShowMillisecond = false;

        boolean isModCountdownInterval = false;
        if (this.isShowDay != isShowDay) {
            this.isShowDay = isShowDay;
            // reset day margins
            if (isShowDay) {
                mSuffixDayLeftMargin = mTempSuffixDayLeftMargin;
                mSuffixDayRightMargin = mTempSuffixDayRightMargin;
            }
        }

        if (this.isShowHour != isShowHour) {
            this.isShowHour = isShowHour;
            // reset hour margins
            if (isShowHour) {
                mSuffixHourLeftMargin = mTempSuffixHourLeftMargin;
                mSuffixHourRightMargin = mTempSuffixHourRightMargin;
            }
        }

        if (this.isShowMinute != isShowMinute) {
            this.isShowMinute = isShowMinute;
            // reset minute margins
            if (isShowMinute) {
                mSuffixMinuteLeftMargin = mTempSuffixMinuteLeftMargin;
                mSuffixMinuteRightMargin = mTempSuffixMinuteRightMargin;
                mSuffixMinute = mTempSuffixMinute;
            }
        }

        if (this.isShowSecond != isShowSecond) {
            this.isShowSecond = isShowSecond;
            isModCountdownInterval = true;

            // reset second margins
            if (isShowSecond) {
                mSuffixSecondLeftMargin = mTempSuffixSecondLeftMargin;
                mSuffixSecondRightMargin = mTempSuffixSecondRightMargin;
                mSuffixSecond = mTempSuffixSecond;
            } else {
                mSuffixMinute = mTempSuffixMinute;
            }

            mSuffixMinuteLeftMargin = mTempSuffixMinuteLeftMargin;
            mSuffixMinuteRightMargin = mTempSuffixMinuteRightMargin;
        }

        if (this.isShowMillisecond != isShowMillisecond) {
            this.isShowMillisecond = isShowMillisecond;
            isModCountdownInterval = true;

            // reset millisecond margins
            if (isShowMillisecond) {
                mSuffixMillisecondLeftMargin = mTempSuffixMillisecondLeftMargin;
            } else {
                mSuffixSecond = mTempSuffixSecond;
            }

            mSuffixSecondLeftMargin = mTempSuffixSecondLeftMargin;
            mSuffixSecondRightMargin = mTempSuffixSecondRightMargin;
        }

        return isModCountdownInterval;
    }

    public boolean handlerAutoShowTime() {
        boolean isReLayout = false;
        if (!mHasSetIsShowDay) {
            if (!isShowDay && mDay > 0) {
                // auto show day
                // judgement auto show hour
                if (!mHasSetIsShowHour) {
                    refTimeShow(true, true, isShowMinute, isShowSecond, isShowMillisecond);
                } else {
                    refTimeShow(true, isShowHour, isShowMinute, isShowSecond, isShowMillisecond);
                }
                isReLayout = true;
            } else if (isShowDay && mDay == 0) {
                // auto hide day
                refTimeShow(false, isShowHour, isShowMinute, isShowSecond, isShowMillisecond);
                isReLayout = true;
            } else {
                if (!mHasSetIsShowHour) {
                    if (!isShowHour && (mDay > 0 || mHour > 0)) {
                        // auto show hour
                        refTimeShow(isShowDay, true, isShowMinute, isShowSecond, isShowMillisecond);
                        isReLayout = true;
                    } else if (isShowHour && mDay == 0 && mHour == 0) {
                        // auto hide hour
                        refTimeShow(false, false, isShowMinute, isShowSecond, isShowMillisecond);
                        isReLayout = true;
                    }
                }
            }
        } else {
            if (!mHasSetIsShowHour) {
                if (!isShowHour && (mDay > 0 || mHour > 0)) {
                    // auto show hour
                    refTimeShow(isShowDay, true, isShowMinute, isShowSecond, isShowMillisecond);
                    isReLayout = true;
                } else if (isShowHour && mDay == 0 && mHour == 0) {
                    // auto hide hour
                    refTimeShow(isShowDay, false, isShowMinute, isShowSecond, isShowMillisecond);
                    isReLayout = true;
                }
            }
        }

        return isReLayout;
    }

    public boolean handlerDayLargeNinetyNine() {
        boolean isReLayout = false;
        if (isShowDay) {
            // handler large ninety nine
            if (!isDayLargeNinetyNine && mDay > 99) {
                isDayLargeNinetyNine = true;
                isReLayout = true;
            } else if (isDayLargeNinetyNine && mDay <= 99) {
                isDayLargeNinetyNine = false;
                isReLayout = true;
            }
        }
        return isReLayout;
    }

    public void setTimes(int day, int hour, int minute, int second, int millisecond) {
        mDay = day;
        mHour = hour;
        mMinute = minute;
        mSecond = second;
        mMillisecond = millisecond;
    }

    public void reLayout() {
        initSuffix();
        initTimeTextBaseInfo();
    }

    public void setTimeTextSize(float textSize) {
        if (textSize > 0) {
            mTimeTextSize = Utils.sp2px(mContext, textSize);
            mTimeTextPaint.setTextSize(mTimeTextSize);

        }
    }

    public void setTimeTextColor(Color textColor) {
        mTimeTextColor = textColor;
        mTimeTextPaint.setColor(mTimeTextColor);
        mComponent.invalidate();
    }

    public void setTimeTextBold(boolean isBold) {
        isTimeTextBold = isBold;
        mTimeTextPaint.setFakeBoldText(isTimeTextBold);
    }

    public void setSuffixTextSize(float textSize) {
        if (textSize > 0) {
            mSuffixTextSize = Utils.sp2px(mContext, textSize);
            mSuffixTextPaint.setTextSize(mSuffixTextSize);
        }
    }

    public void setSuffixTextColor(Color textColor) {
        mSuffixTextColor = textColor;
        mSuffixTextPaint.setColor(mSuffixTextColor);
        mComponent.invalidate();
    }

    public void setSuffixTextBold(boolean isBold) {
        isSuffixTextBold = isBold;
        mSuffixTextPaint.setFakeBoldText(isSuffixTextBold);
    }

    public void setSuffix(String suffix) {
        mSuffix = suffix;
        setSuffix(mSuffix, mSuffix, mSuffix, mSuffix, mSuffix);
    }

    public boolean setConvertDaysToHours(boolean isConvertDaysToHours) {
        if (this.isConvertDaysToHours == isConvertDaysToHours) return false;
        this.isConvertDaysToHours = isConvertDaysToHours;
        return true;
    }

    public boolean setSuffix(String suffixDay, String suffixHour, String suffixMinute, String suffixSecond, String suffixMillisecond) {
        boolean isRef = false;

        if (null != suffixDay) {
            mSuffixDay = suffixDay;
            isRef = true;
        }

        if (null != suffixHour) {
            mSuffixHour = suffixHour;
            isRef = true;
        }

        if (null != suffixMinute) {
            mSuffixMinute = suffixMinute;
            isRef = true;
        }

        if (null != suffixSecond) {
            mSuffixSecond = suffixSecond;
            isRef = true;
        }

        if (null != suffixMillisecond) {
            mSuffixMillisecond = suffixMillisecond;
            isRef = true;
        }

        if (isRef) initSuffixBase();

        return isRef;
    }

    public void setSuffixLRMargin(float suffixLRMargin) {
        mSuffixLRMargin = Utils.dp2px(mContext, suffixLRMargin);
        setSuffixMargin(mSuffixDayLeftMargin, mSuffixDayLeftMargin,
                mSuffixDayLeftMargin, mSuffixDayLeftMargin,
                mSuffixDayLeftMargin, mSuffixDayLeftMargin,
                mSuffixDayLeftMargin, mSuffixDayLeftMargin,
                mSuffixDayLeftMargin);
    }

    public boolean setSuffixMargin(Float suffixDayMarginL, Float suffixDayMarginR,
                                   Float suffixHourMarginL, Float suffixHourMarginR,
                                   Float suffixMinuteMarginL, Float suffixMinuteMarginR,
                                   Float suffixSecondMarginL, Float suffixSecondMarginR,
                                   Float suffixMillisecondMarginL) {
        boolean isRef = false;

        if (null != suffixDayMarginL) {
            mSuffixDayLeftMargin = Utils.dp2px(mContext, suffixDayMarginL);
            isRef = true;
        }
        if (null != suffixDayMarginR) {
            mSuffixDayRightMargin = Utils.dp2px(mContext, suffixDayMarginR);
            isRef = true;
        }

        if (null != suffixHourMarginL) {
            mSuffixHourLeftMargin = Utils.dp2px(mContext, suffixHourMarginL);
            isRef = true;
        }
        if (null != suffixHourMarginR) {
            mSuffixHourRightMargin = Utils.dp2px(mContext, suffixHourMarginR);
            isRef = true;
        }

        if (null != suffixMinuteMarginL) {
            mSuffixMinuteLeftMargin = Utils.dp2px(mContext, suffixMinuteMarginL);
            isRef = true;
        }
        if (null != suffixMinuteMarginR) {
            mSuffixMinuteRightMargin = Utils.dp2px(mContext, suffixMinuteMarginR);
            isRef = true;
        }

        if (null != suffixSecondMarginL) {
            mSuffixSecondLeftMargin = Utils.dp2px(mContext, suffixSecondMarginL);
            isRef = true;
        }
        if (null != suffixSecondMarginR) {
            mSuffixSecondRightMargin = Utils.dp2px(mContext, suffixSecondMarginR);
            isRef = true;
        }

        if (null != suffixMillisecondMarginL) {
            mSuffixMillisecondLeftMargin = Utils.dp2px(mContext, suffixMillisecondMarginL);
            isRef = true;
        }


        if (isRef) initTempSuffixMargin();

        return isRef;
    }

    public void setSuffixGravity(int suffixGravity) {
        mSuffixGravity = suffixGravity;

        mComponent.invalidate();
    }

}

